<template>
  <div v-bind="$attrs" ref="chartRef" class="line-bar-chart"></div>
</template>

<script lang="ts" setup>
/*
 * initData: 除了数据外的其他设置
 * {
 *   title: '覆盖原始title对象设置',  // title与titleText选一
 *   titleText: '设置title.text'，  // title与titleText选一
 *   yAxis: [{}, ...] || {},   // 可选，重复的一级属性无需再设置，若设置了一级属性，则一级属性的属性会被覆盖
 *   xAxis: [{}, ...] || {},   // 可选，同上
 *   legend: {},  // 可选，同上
 *   series: [{}, ...] || {},  // 可选，同上
 *   seriesColor: [seriesColor(维度颜色), seriesColor(维度颜色)] // 可选
 *   * * seriesColor:  string || object
 *           1、如果是纯色，设置颜色字符串;
 *           2、如果是渐变色，需要设置成{start: color1, end: color2};
 *   dataset: {}, // 可选，dataset
 *   dataZoom: [],// 可选，会直接覆盖
 * }
 * updateData: {
 *  series?: [] | {},
 *  dataset?: [] | {},
 * }
 * */
import * as echarts from "echarts/core";
import {
  BarChart,
  BarSeriesOption,
  LineChart,
  LineSeriesOption,
} from "echarts/charts";
import {
  TitleComponent,
  // 组件类型的定义后缀都为 ComponentOption
  TitleComponentOption,
  TooltipComponent,
  TooltipComponentOption,
  GridComponent,
  GridComponentOption,
  LegendComponent,
  LegendComponentOption,
  // 数据集组件
  DatasetComponent,
  DatasetComponentOption,
  // 内置数据转换器组件 (filter, sort)
  TransformComponent,
} from "echarts/components";
// import { LabelLayout, UniversalTransition } from "echarts/features";
import { CanvasRenderer } from "echarts/renderers";

import {
  axisLineColor,
  titleColor,
  axisLabelColor,
  seriesColor,
  tooltipFormatter,
  tooltipBgColor,
} from "./const";
import { cloneDeep } from "lodash";
import type { RequiredAtLeastOne } from "#/index";
import type { AddEchartInstance } from "@/layout";

// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
type ECOption = echarts.ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | GridComponentOption
  | DatasetComponentOption
  | LegendComponentOption
>;

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  LegendComponent,
  DatasetComponent,
  TransformComponent,
  BarChart,
  LineChart,
  // LabelLayout,
  // UniversalTransition,
  CanvasRenderer,
]);

// InitData
interface InitDataOrigin {
  title?: object;
  titleText?: string;
  [key: string]: any;
}
type InitData = RequiredAtLeastOne<InitDataOrigin, "title" | "titleText">;
// UpdateData
interface SeriesItem {
  data: Array<string | number>;
}
interface Dataset {
  source: Array<object> | object;
}
interface UpdateDataOrigin {
  series?: Array<SeriesItem>;
  dataset?: Dataset;
}
type UpdateData = RequiredAtLeastOne<UpdateDataOrigin, "series" | "dataset">;
interface Props {
  initData: InitData;
  updateData: UpdateData;
  unit?: string; // 设置悬浮窗数字的单位
}
const props = defineProps<Props>();
let myChart: echarts.ECharts;
const chartRef = ref();

const addAfterEnterFuncs: AddEchartInstance | undefined =
  inject("addAfterEnterFuncs");

watch(
  () => props.updateData,
  (val: UpdateData) => {
    myChart && myChart.clear();
    nextTick(() => {
      updateDataChange(val);
    });
  }
);

function checkData(val: UpdateData) {
  return (
    val.toString() === "[object Object]" &&
    Object.keys(val).length > 0 &&
    ((val.series &&
      val.series.length > 0 &&
      val.series.filter((item: SeriesItem) => item.data && item.data.length > 0)
        .length > 0) ||
      (val.dataset &&
        val.dataset.source &&
        ((Array.isArray(val.dataset.source) && val.dataset.source.length) ||
          Object.keys(val.dataset.source).length)))
  );
}
let addFlag = false;
const updateDataChange = (val: UpdateData) => {
  if (checkData(val)) {
    console.log("line", myChart);
    if (!addFlag) {
      addAfterEnterFuncs && addAfterEnterFuncs(renderChart);
      addFlag = true;
    } else {
      renderChart();
    }
  }
};
const renderChart = () => {
  initChart();
  updateChart();
};

const updateChart = () => {
  const config: UpdateData = { series: [] };
  const mixinSeries = getSeries();
  const otherConfig = cloneDeep(props.updateData);
  otherConfig.series && delete otherConfig.series;
  otherConfig.dataset && delete otherConfig.dataset;
  if (props.updateData.dataset) {
    config.dataset = props.updateData.dataset;
    config.series = mixinSeries;
  }
  if (props.updateData.series) {
    config.series = props.updateData.series.map((s, index) => {
      return {
        ...mixinSeries[index],
        ...s,
      };
    });
  }
  myChart.setOption({
    ...config,
    ...otherConfig,
  });
};

const initChart = () => {
  myChart = myChart || echarts.init(chartRef.value as HTMLElement);

  const option: ECOption = {
    title: props.initData.title || {
      text: props.initData.titleText,
      left: 0,
      textStyle: {
        color: titleColor,
        fontSize: "16px",
        fontWeight: "normal",
      },
    },
    legend: {
      show: true,
      type: "scroll",
      right: 0,
      itemWidth: 14,
      itemHeight: 14,
      itemGap: 4,
      textStyle: {
        color: axisLabelColor,
        fontSize: 12,
      },
      ...(props.initData.legend || {}),
    },
    tooltip: {
      show: true,
      trigger: "axis",
      confine: true,
      padding: 10,
      backgroundColor: tooltipBgColor,
      borderWidth: 0,
      textStyle: {
        fontSize: 14,
        color: "#dAe8fd",
      },
      formatter: tooltipFormatter(props.unit),
      ...(props.initData.tooltip || {}),
    },
    //                    dataZoom: props.initData.dataZoom || [{
    //                        type: 'inside',
    //                        maxValueSpan: 11,
    //                        minValueSpan: 2,
    //                        start: 0
    //                    }],
    grid: {
      top: 35,
      left: 5,
      right: 2,
      bottom: 0,
      containLabel: true,
      ...(props.initData.grid || {}),
    },
    xAxis: getXAxis(),
    yAxis: getYAxis(),
    dataset: {
      // 提供一份数据。
      source: [],
    },
    series: [],
  };
  myChart.setOption(option);
};
const getSeries = () => {
  const initConfig = {
    type: "line",
    showSymbol: false,
    label: {
      show: false,
    },
    lineStyle: {
      width: 2,
    },
    emphasis: {
      focus: "series",
    },
  };
  const initSeries = props.initData.series;
  // 自定义配置了series，按照用户配置的series显示数据的维度
  if (initSeries) {
    // 如果是数组，遍历数组每一项 并 合并配置
    if (Array.isArray(initSeries)) {
      return initSeries.map((item, index) => {
        return {
          ...initConfig,
          itemStyle: {
            color: getColor(index),
          },
          ...item,
        };
      });
    }
  }

  /* 根据updateData中的series或者source设置series数组 */
  let arr = [];
  // 如果 配置了series
  if (props.updateData.series) {
    const updateSeries = props.updateData.series;
    const len = (Array.isArray(updateSeries) ? updateSeries : [updateSeries])
      .length;
    arr = new Array(len).fill("");
  } else if (props.updateData.dataset) {
    // 配置了source
    // 否则根据dataset中的数据显示维度
    const source = props.updateData.dataset.source;
    if (source instanceof Array) {
      if (source.length > 0) {
        if (source[0] instanceof Array) {
          arr = new Array(source[0].length - 1).fill("");
        } else if (source[0].toString() === "[object Object]") {
          // source[0]是对象
          arr = new Array(Object.keys(source[0]).length - 1).fill("");
        } else {
          Error("echarts updateData.source[0]必须是对象或数组");
        }
      }
    } else if (source.toString() === "[object Object]") {
      arr = new Array(Object.keys(source).length - 1).fill("");
    } else {
      Error("echarts updateData.source必须是对象或数组");
    }
  }
  return arr.reduce((prev, item, index) => {
    return prev.concat({
      ...initConfig,
      itemStyle: {
        color: getColor(index),
      },
      ...(initSeries || {}),
    });
  }, []);
};
// 获取某个维度的柱子颜色
const getColor = (i = 0) => {
  return (
    (props.initData.seriesColor && props.initData.seriesColor[i]) ||
    seriesColor[i]
  );
};
const getXAxis = () => {
  const initConfig = {
    type: "category",
    axisLine: {
      show: true,
      lineStyle: {
        color: axisLabelColor,
        width: 1,
      },
    },
    axisTick: {
      show: true,
    },
    axisLabel: {
      interval: 0,
      color: axisLabelColor,
      fontSize: 12,
    },
    splitLine: {
      show: false,
    },
  };
  return mergeConfig(initConfig, props.initData.xAxis);
};
const getYAxis = () => {
  const initConfig = {
    axisLine: {
      show: false,
    },
    axisTick: {
      show: false,
    },
    axisLabel: {
      color: axisLabelColor,
      fontSize: 12,
    },
    splitLine: {
      show: true,
      lineStyle: {
        color: axisLineColor,
        width: 1,
      },
    },
    nameTextStyle: {
      color: axisLabelColor,
      fontSize: 14,
    },
    ...(props.initData.yAxis || {}),
  };
  return mergeConfig(initConfig, props.initData.yAxis);
};
const mergeConfig = (initConfig: object, newConfig: object[] | object) => {
  if (Array.isArray(newConfig)) {
    return newConfig.map((item, index) => {
      return { ...initConfig, ...newConfig[index] };
    });
  } else if (newConfig instanceof Object) {
    return { ...initConfig, ...newConfig };
  } else {
    return initConfig;
  }
};
</script>
